package cn.com.cfae.iras.doc.analyze.parse.extractor;

import cn.com.cfae.iras.doc.analyze.parse.kv.KVText;
import cn.com.cfae.iras.doc.analyze.parse.kv.TextLayout;
import cn.com.cfae.iras.doc.analyze.parse.model.*;
import cn.com.cfae.iras.doc.analyze.parse.tokenizer.DWDBTokenizer;
import cn.com.cfae.iras.doc.analyze.parse.tokenizer.ZCFZTokenizer;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.InvocationTargetException;
import java.util.*;

/**
 * M6章节数据抽取
 */
public class M6Extractor extends MTableExtractor {
    private static final Logger logger = LoggerFactory.getLogger(M6Extractor.class);

    private ZCFZTokenizer zcfzTokenizer = ZCFZTokenizer.getInstance();

    private DWDBTokenizer dwdbTokenizer = DWDBTokenizer.getInstance();

    @Override
    public void extract() {
        try {
            extractM6();
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
    }

    private void extractM6() {
        long t1 = System.currentTimeMillis();
        logger.info("开始抽取{}章业务模型数据......", getChapterModel().getChapterId());
        try {
            extractM6ZCFZ();
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        try {
            extractM6XJLL();
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        try {
            extractM6LR();
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }

        try {
            parseChapterSection();
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
//会计科目分析-资产负债
        try {
            extractM6KJKMFX_ZCFZ();
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
//会计科目分析-现金流量
        try {
            extractM6KJKMFX_XJLL();
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        //会计科目分析-利润
        try {
            extractM6KJKMFX_LR();
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }

        try {
            extractM6CZNL2();
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }

        try {
            extractM6YLNL2();
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }

        try {
            extractM6YYNL2();
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }

        try {
            extractM6DWDBJE();
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        try {
            extractM6Sxzc2();
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        long t2 = System.currentTimeMillis();
        logger.info("抽取{}章业务模型数据完成，耗时：{}毫秒。", getChapterModel().getChapterId(), (t2 - t1));
    }


    /**
     * 对外担保金额
     */
    private void extractM6Sxzc2() {
        long t1 = System.currentTimeMillis();
        logger.info("开始抽取：{}章受限资产业务模型......", getChapterModel().getChapterId());
        List<PageModel> pageModelList = getPageModelList();
        PageModel pageModel = null;
        List<PageArea> pageAreaList = new ArrayList<>();
        TextLayout startTextLayout = null;
        TextLayout endTextLayout = null;
        ExtractBizModel extractBizModel = getChapterModel().getExtractBizModelMap().get("SXZC");
        ExtractItem extractItem = extractBizModel.getExtractItem("SXZC");
        for (int i = 0; i < pageModelList.size(); i++) {
            pageModel = pageModelList.get(i);
            if (pageModel == null) {
                continue;
            }
            JsonArray itemArray = getPageDataArray(pageModel);
            for (int j = 0; j < itemArray.size(); j++) {
                JsonArray items = itemArray.get(j).getAsJsonArray();
                String combineLine = combineTextJsonArray(items);
                if (isEmpty(combineLine)) {
                    continue;
                }
                if (isProspectus(combineLine)) {
                    continue;
                }
                if (j == (itemArray.size() - 1)) {
                    if (getPageModelBottomPageNum(items) > 0) {
                        logger.info("抽取：{}章受限资产业务模型，当前页码：{}，已分析到该页末尾，到下一页定位受限资产信息表结束位置。", getChapterModel().getChapterId(), pageModel.getPageNumber());
                        break;
                    }
                }
                if (isSXZC(combineLine)) {
                    setTableNameTextLayout(pageModel, extractBizModel, items);
                    if (startTextLayout != null) {
                        endTextLayout = createKVTextLayout(pageModel, items);
                        logger.info("抽取：{}章受限资产业务模型，分析定位到受限资产表格结束位置，结束页码：{}。", getChapterModel().getChapterId(), combineLine);
                        pageAreaList.addAll(createPageArea(startTextLayout, endTextLayout));
                        startTextLayout = null;
                        endTextLayout = null;
                    }
                    logger.info("抽取：{}章受限资产业务模型，分析定位受限资产表格起始位置，起始页码：{}，表头信息：{}。", getChapterModel().getChapterId(), pageModel.getPageNumber(), combineLine);
                    startTextLayout = createKVTextLayout(pageModel, items);
                    continue;
                }
                if (isInner3(items, pageModel)) {
                    continue;
                } else if (startTextLayout != null) {
                    if (isAmtUnit(combineLine)) {
                        setTableUnitType(extractBizModel, combineLine);
                        continue;
                    }
                    endTextLayout = createKVTextLayout(pageModel, items);
                    logger.info("抽取：{}章受限资产业务模型，分析定位到受限资产表格结束位置，结束页码：{}。", getChapterModel().getChapterId(), combineLine);
                    pageAreaList.addAll(createPageArea(startTextLayout, endTextLayout));
                    break;
//                    startTextLayout = null;
//                    endTextLayout = null;
//                    continue;
                }
            }
            if (startTextLayout != null && endTextLayout != null) {
                break;
            }
        }
        if (CollectionUtils.isEmpty(pageAreaList)) {
            logger.error("抽取：{}章受限资产业务模型，分析定位受限资产表格位置失败！！！", getChapterModel().getChapterId());
            return;
        }
        logger.info("抽取：{}章受限资产业务模型，分析定位到受限资产表格位置，开始提取数据......", getChapterModel().getChapterId());
        boolean isCandicate = false;
        try {
            PageArea pageArea = null;
            for (int i = 0; i < pageAreaList.size(); i++) {
                pageArea = pageAreaList.get(i);
                logger.info("抽取{}章受限资产业务模型，当前页码：{}，表格区域：{}。", getChapterModel().getChapterId(), pageArea.getPageNumber(), pageArea.getLayout());
                List<String> pageTableDataList = extractPdfByTable(new String[]{getDocumentModel().getPdfFilePath(), "-l", "-p", String.valueOf(pageArea.getPageNumber()), "-a", pageArea.getLayout(), "-f", "JSON"});
                logger.info("抽取{}章受限资产业务模型，当前页码：{}，表格数量：{}，表格数据：{}。", getChapterModel().getChapterId(), pageArea.getPageNumber(), pageTableDataList.size(), pageTableDataList);
                if (isCandicate) {
                    break;
                }
                if (pageTableDataList.isEmpty()) {
                    continue;
                }
                for (String tableData : pageTableDataList) {
                    logger.info("抽取{}章受限资产业务模型，第{}页，数据：{}。", getChapterModel().getChapterId(), pageArea.getPageNumber(), tableData);
                    JsonArray pageData = str2Json(tableData).getAsJsonArray();
                    JsonObject var1 = pageData.get(0).getAsJsonObject();
                    JsonArray var2 = var1.get("data").getAsJsonArray();
                    if (var2.size() <= 0) {
                        continue;
                    }
                    int hjOffset = -1;
                    for (int j = 0; j < var2.size(); j++) {
                        JsonArray dataArray = var2.get(j).getAsJsonArray();
                        for (int k = 0; k < dataArray.size(); k++) {
                            JsonObject hjJsonObject = dataArray.get(k).getAsJsonObject();
                            String text = hjJsonObject.get("text").getAsString().trim();
                            if (isEmpty(text)) {
                                continue;
                            }
                            if (isHJFormat(text)) {
                                hjOffset = j;
                                break;
                            }
                        }
                    }
                    if (hjOffset < 0) {
                        logger.error("抽取{}章受限资产业务模型，未能分析定位到受限资产合计位置！！！", getChapterModel().getChapterId());
                        continue;
                    }
                    JsonArray dataArray = var2.get(hjOffset).getAsJsonArray();
                    for (int j = 0; j < dataArray.size(); j++) {
                        JsonObject cell = dataArray.get(j).getAsJsonObject();
                        String cellText = cell.get("text").getAsString().trim();
                        if (isEmpty(cellText)) {
                            continue;
                        }
                        if (isSXZC_JE(cellText.replaceAll(",", ""))) {
                            logger.info("抽取{}章受限资产业务模型，分析定位到受限资产金额，指标名称：{}，指标值：{}。", getChapterModel().getChapterId(), extractItem.getItemName(), cellText);
                            KVText vText = new KVText();
                            vText.setText(cellText);
                            vText.add(createKVTextLayout(cell));
                            extractItem.setValue(vText);
                            isCandicate = true;
                            break;
                        }
                    }
                }
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        logger.info("抽取{}章受限资产业务模型，受限资产数据结构：{}。", getChapterModel().getChapterId(), obj2Json(extractBizModel));
        long t2 = System.currentTimeMillis();
        logger.info("抽取{}章受限资产业务模型完成，耗时：{}毫秒。", getChapterModel().getChapterId(), (t2 - t1));
    }


    /**
     * 对外担保金额
     */
    private void extractM6Dwdbje3() {
        long t1 = System.currentTimeMillis();
        logger.info("开始抽取：{}章对外担保业务模型-表格形式......", getChapterModel().getChapterId());
        List<PageModel> pageModelList = getPageModelList();
        PageModel pageModel = null;
        List<PageArea> pageAreaList = new ArrayList<>();
        TextLayout startTextLayout = null;
        TextLayout endTextLayout = null;
        ExtractBizModel extractBizModel = getChapterModel().getExtractBizModelMap().get("DWDB");
        ExtractItem extractItem = extractBizModel.getExtractItem("DWDBJE");
        for (int i = 0; i < pageModelList.size(); i++) {
            pageModel = pageModelList.get(i);
            if (pageModel == null) {
                continue;
            }
            JsonArray itemArray = getPageDataArray(pageModel);
            for (int j = 0; j < itemArray.size(); j++) {
                JsonArray items = itemArray.get(j).getAsJsonArray();
                String combineLine = combineTextJsonArray(items);
                if (isEmpty(combineLine)) {
                    continue;
                }
                if (j == (itemArray.size() - 1)) {
                    if (getPageModelBottomPageNum(items) > 0) {
                        logger.info("抽取：{}章对外担保业务模型-表格形式，当前页码：{}，已分析到该页末尾，到下一页定位对外担保信息表结束位置。", getChapterModel().getChapterId(), pageModel.getPageNumber());
                        break;
                    }
                }
                if (isDWDB(combineLine)) {
                    setTableNameTextLayout(pageModel, extractBizModel, items);
                    if (startTextLayout != null) {
                        endTextLayout = createKVTextLayout(pageModel, items);
                        logger.info("抽取：{}章对外担保业务模型-表格形式，分析定位到对外担保情况表格结束位置，结束页码：{}。", getChapterModel().getChapterId(), combineLine);
                        pageAreaList.addAll(createPageArea(startTextLayout, endTextLayout));
                        startTextLayout = null;
                        endTextLayout = null;
                    }
                    logger.info("抽取：{}章对外担保业务模型-表格形式，分析定位对外担保表格起始位置，开始页码：{}，表头信息：{}。", getChapterModel().getChapterId(), combineLine);
                    startTextLayout = createKVTextLayout(pageModel, items);
                    continue;
                }
                if (isInner3(items, pageModel)) {
                    continue;
                } else if (startTextLayout != null) {
                    if (isAmtUnit(combineLine)) {
                        setTableUnitType(extractBizModel, combineLine);
                        continue;
                    }
                    endTextLayout = createKVTextLayout(pageModel, items);
                    logger.info("抽取：{}章对外担保业务模型-表格形式，分析定位到对外担保表格结束位置，结束页码：{}。", getChapterModel().getChapterId(), combineLine);
                    pageAreaList.addAll(createPageArea(startTextLayout, endTextLayout));
                    break;
//                    startTextLayout = null;
//                    endTextLayout = null;
//                    continue;
                }
            }
            if (startTextLayout != null && endTextLayout != null) {
                break;
            }
        }
        if (CollectionUtils.isEmpty(pageAreaList)) {
            logger.info("抽取：{}章对外担保业务模型-表格形式，分析定位对外担保表格位置失败！！！", getChapterModel().getChapterId());
            return;
        }
        logger.info("抽取：{}章对外担保业务模型-表格形式，分析定位到对外担保表格位置，开始提取数据......", getChapterModel().getChapterId());
        try {
            boolean isCandicate = false;
            PageArea pageArea = null;
            for (int i = 0; i < pageAreaList.size(); i++) {
                pageArea = pageAreaList.get(i);
                logger.info("抽取{}章对外担保业务模型-表格形式，当前页码：{}，表格区域：{}。", getChapterModel().getChapterId(), pageArea.getPageNumber(), pageArea.getLayout());
                List<String> pageTableDataList = extractPdfByTable(new String[]{getDocumentModel().getPdfFilePath(), "-l", "-p", String.valueOf(pageArea.getPageNumber()), "-a", pageArea.getLayout(), "-f", "JSON"});
                logger.info("抽取{}章对外担保业务模型-表格形式，当前页码：{}，表格数量：{}，表格数据：{}。", getChapterModel().getChapterId(), pageArea.getPageNumber(), pageTableDataList.size(), pageTableDataList);
                if (isCandicate) {
                    break;
                }
                if (pageTableDataList.isEmpty()) {
                    continue;
                }
                for (String tableData : pageTableDataList) {
                    logger.info("抽取{}章对外担保业务模型-表格形式，第{}页，表格数据：{}。", getChapterModel().getChapterId(), pageArea.getPageNumber(), tableData);
                    JsonArray pageData = str2Json(tableData).getAsJsonArray();
                    JsonObject var1 = pageData.get(0).getAsJsonObject();
                    JsonArray var2 = var1.get("data").getAsJsonArray();
                    if (var2.size() <= 0) {
                        continue;
                    }
                    int hjOffset = -1;
                    for (int j = 0; j < var2.size(); j++) {
                        JsonArray dataArray = var2.get(j).getAsJsonArray();
                        for (int k = 0; k < dataArray.size(); k++) {
                            JsonObject hjJsonObject = dataArray.get(k).getAsJsonObject();
                            String text = hjJsonObject.get("text").getAsString().trim();
                            if (isEmpty(text)) {
                                continue;
                            }
                            if (isHJFormat(text)) {
                                hjOffset = j;
                                break;
                            }
                        }
                    }
                    if (hjOffset < 0) {
                        logger.error("抽取{}章对外担保业务模型-表格形式，未能分析定位到对外担保金额合计位置！！！", getChapterModel().getChapterId());
                        continue;
                    }
                    JsonArray dataArray = var2.get(hjOffset).getAsJsonArray();
                    for (int j = 0; j < dataArray.size(); j++) {
                        JsonObject cell = dataArray.get(j).getAsJsonObject();
                        String cellText = cell.get("text").getAsString().trim();
                        if (isEmpty(cellText)) {
                            continue;
                        }
                        if (isDWDB_JE(cellText.replaceAll(",", ""))) {
                            logger.info("抽取{}章对外担保业务模型-表格形式，分析定位到对外担保金额，指标名称：{}，指标值：{}。", getChapterModel().getChapterId(), extractItem.getItemName(), cellText);
                            KVText vText = new KVText();
                            vText.setText(cellText);
                            vText.add(createKVTextLayout(cell));
                            extractItem.setValue(vText);
                            isCandicate = true;
                            break;
                        }
                    }
                }
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        logger.info("抽取{}章对外担保业务模型-表格形式，对外担保数据结构：{}。", getChapterModel().getChapterId(), obj2Json(extractBizModel));
        long t2 = System.currentTimeMillis();
        logger.info("抽取{}章对外担保业务模型-表格形式完成，耗时：{}毫秒。", getChapterModel().getChapterId(), (t2 - t1));
    }

    /**
     * 对外担保金额
     *
     * @param
     */
    private void extractM6DWDBJE() {
        long t1 = System.currentTimeMillis();
        logger.info("开始抽取{}章对外担保业务模型......", getChapterModel().getChapterId());
        ExtractBizModel extractBizModel = getChapterModel().getExtractBizModelMap().get("DWDB");
        dwdbTokenizer.loadCoreSynonyms(extractBizModel);
        ExtractItem extractItem = extractBizModel.getExtractItem("DWDBJE");
        List<SectionModel> sectionModelList = getChapterModel().getSectionModelList();
        if (CollectionUtils.isEmpty(sectionModelList)) {
            logger.error("抽取{}章对外担保业务模型-文本形式，分析内容为空，请确认！！！", getChapterModel().getChapterId());
            return;
        }
        for (int i = 0; i < sectionModelList.size(); i++) {
            SectionModel sectionModel = sectionModelList.get(i);
            List<SectionModel> childSectionModelList = sectionModel.getChildSectionModelList();
            if (CollectionUtils.isEmpty(childSectionModelList)) {
                continue;
            }
            for (int j = 0; j < childSectionModelList.size(); j++) {
                SectionModel childSectionModel = childSectionModelList.get(j);
                String content = childSectionModel.getContent();
                if (isEmpty(content)) {
                    continue;
                }
                logger.info("抽取{}章对外担保业务模型-文本形式，分析文本：{}。", getChapterModel().getChapterId(), childSectionModel.getTitle());
                dwdbTokenizer.splitWords6(extractBizModel, childSectionModel);
            }
        }
        dwdbTokenizer.unloadCoreSynonyms(extractBizModel);
        if (extractItem == null || (extractItem.getKey() == null || extractItem.getValue() == null)) {
            extractM6Dwdbje3();
        }
        long t2 = System.currentTimeMillis();
        logger.info("抽取{}章对外担保业务模型完成，耗时：{}毫秒。", getChapterModel().getChapterId(), (t2 - t1));
    }

    private void extractM6KJKMFX_ZCFZ() {
        ChapterModel child = null;
        //TODO 先这么弄吧
        switch (getBaseTable().getTableType()) {
            case M:
                child = getChapterModel().createChildChapterModel("M-6-2");
                child.setExtractBizModelMap(getBaseTable().getExtractBizModelMap("M-6"));
                break;
            case BM:
                child = getChapterModel().createChildChapterModel("BM-6-2");
                child.setExtractBizModelMap(getBaseTable().getExtractBizModelMap("BM-6"));
                break;
        }
        ExtractBizModel extractBizModel = child.getExtractBizModelMap().get("ZCFZ");
        long t1 = System.currentTimeMillis();
        logger.info("开始抽取{}章会计科目分析-资产负债......", child.getChapterId());
        zcfzTokenizer.loadCoreSynonyms(extractBizModel);
        List<SectionModel> sectionModelList = getChapterModel().getSectionModelList();
        if (CollectionUtils.isEmpty(sectionModelList)) {
            logger.error("抽取{}章会计科目分析-资产负债，会计科目分析列表为空，请确认！！！", child.getChapterId());
            return;
        }
        try {
            for (int i = 0; i < sectionModelList.size(); i++) {
                SectionModel sectionModel = sectionModelList.get(i);
                List<SectionModel> childSectionModelList = sectionModel.getChildSectionModelList();
                if (CollectionUtils.isEmpty(childSectionModelList)) {
                    continue;
                }
                for (int j = 0; j < childSectionModelList.size(); j++) {
                    SectionModel childSectionModel = childSectionModelList.get(j);
                    if (childSectionModel == null) {
                        continue;
                    }
                    String content = childSectionModel.getContent();
                    if (isEmpty(content)) {
                        continue;
                    }
                    logger.info("抽取{}章会计科目分析-资产负债，指标名称：{}，分析文本：{}。", getChapterModel().getChapterId(), extractBizModel.getModelName(), childSectionModel.getTitle());
                    try {
                        zcfzTokenizer.splitWords5(extractBizModel, childSectionModel);
                    } catch (Exception e) {
                        logger.error(e.getMessage(), e);
                        continue;
                    }
                }
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        zcfzTokenizer.unloadCoreSynonyms(extractBizModel);
        long t2 = System.currentTimeMillis();
        logger.info("抽取{}章会计科目分析-资产负债完成，耗时：{}毫秒。", child.getChapterId(), (t2 - t1));
    }

    private void extractM6KJKMFX_XJLL() {
        ChapterModel child = null;
        switch (getBaseTable().getTableType()) {
            case M:
                child = getChapterModel().createChildChapterModel("M-6-2");
                break;
            case BM:
                child = getChapterModel().createChildChapterModel("BM-6-2");
                break;
        }

        long t1 = System.currentTimeMillis();
        logger.info("开始抽取{}章会计科目分析-现金流量......", child.getChapterId());
        ExtractBizModel extractBizModel = child.getExtractBizModelMap().get("XJLL");
        try {
            List<SectionModel> sectionModelList = getChapterModel().getSectionModelList();
            if (CollectionUtils.isEmpty(sectionModelList)) {
                logger.error("抽取{}章会计科目分析-现金流量，会计科目分析列表为空，请确认！！！", child.getChapterId());
                return;
            }
            for (int i = 0; i < sectionModelList.size(); i++) {
                SectionModel sectionModel = sectionModelList.get(i);
                List<SectionModel> childSectionModelList = sectionModel.getChildSectionModelList();
                if (CollectionUtils.isEmpty(childSectionModelList)) {
                    continue;
                }
                for (int j = 0; j < childSectionModelList.size(); j++) {
                    SectionModel childSectionModel = childSectionModelList.get(j);
                    if (childSectionModel == null) {
                        continue;
                    }
                    String content = childSectionModel.getContent();
                    if (isEmpty(content)) {
                        continue;
                    }
                    logger.info("抽取{}章会计科目分析-现金流量，指标名称：{}，分析文本：{}。", getChapterModel().getChapterId(), extractBizModel.getModelName(), childSectionModel.getTitle());
                    try {
                        zcfzTokenizer.splitWords5(extractBizModel, childSectionModel);
                    } catch (Exception e) {
                        logger.error(e.getMessage(), e);
                        continue;
                    }
                }
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        zcfzTokenizer.unloadCoreSynonyms(extractBizModel);
        long t2 = System.currentTimeMillis();
        logger.info("抽取{}章会计科目分析-现金流量完成，耗时：{}毫秒。", child.getChapterId(), (t2 - t1));

    }

    private void extractM6KJKMFX_LR() {
        ChapterModel child = null;
        switch (getBaseTable().getTableType()) {
            case M:
                child = getChapterModel().createChildChapterModel("M-6-2");
                break;
            case BM:
                child = getChapterModel().createChildChapterModel("BM-6-2");
                break;
        }
        long t1 = System.currentTimeMillis();
        logger.info("开始抽取{}章会计科目分析-利润......", child.getChapterId());
        ExtractBizModel extractBizModel = child.getExtractBizModelMap().get("LR");
        List<SectionModel> sectionModelList = getChapterModel().getSectionModelList();
        if (CollectionUtils.isEmpty(sectionModelList)) {
            logger.error("抽取{}章会计科目分析-利润，会计科目分析列表为空，请确认！！！", child.getChapterId());
            return;
        }
        try {
            for (int i = 0; i < sectionModelList.size(); i++) {
                SectionModel sectionModel = sectionModelList.get(i);
                List<SectionModel> childSectionModelList = sectionModel.getChildSectionModelList();
                if (CollectionUtils.isEmpty(childSectionModelList)) {
                    continue;
                }
                for (int j = 0; j < childSectionModelList.size(); j++) {
                    SectionModel childSectionModel = childSectionModelList.get(j);
                    if (childSectionModel == null) {
                        continue;
                    }
                    String content = childSectionModel.getContent();
                    if (isEmpty(content)) {
                        continue;
                    }
                    logger.info("抽取{}章会计科目分析-利润，指标名称：{}，分析文本：{}。", getChapterModel().getChapterId(), extractBizModel.getModelName(), childSectionModel.getTitle());
                    try {
                        zcfzTokenizer.splitWords5(extractBizModel, childSectionModel);
                    } catch (Exception e) {
                        logger.error(e.getMessage(), e);
                        continue;
                    }
                }
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        zcfzTokenizer.unloadCoreSynonyms(extractBizModel);
        long t2 = System.currentTimeMillis();
        logger.info("抽取{}章会计科目分析-利润完成，耗时：{}毫秒。", child.getChapterId(), (t2 - t1));
    }

    /**
     * M-6-1资产负债
     */
    private void extractM6ZCFZ() {
        long t1 = System.currentTimeMillis();
        logger.info("开始抽取{}章合并资产负债表......", getChapterModel().getChapterId());
        ExtractBizModel extractBizModel = getChapterModel().getExtractBizModelMap().get("ZCFZ");
        List<PageModel> pageModeList = getPageModelList();
        logger.info("开始抽取{}章合并资产负债表，分析页码总数：{}。", getChapterModel().getChapterId(), pageModeList.size());
        List<PageArea> pageAreas = new ArrayList<>();
        int startPage = 0, endPage = 0;
        double width = 0, height = 0;
        logger.info("抽取{}章合并资产负债表，分析定位表格区域......", getChapterModel().getChapterId());
        List<YearIndex> yearIndexList = new ArrayList<>();
        for (int i = 0; i < pageModeList.size(); i++) {
            PageModel pageModel = pageModeList.get(i);
            JsonElement jsonElement = pageModel.getJsonTextData();
            logger.info("抽取{}章合并资产负债表，当前页码：{}，分析文本：{}。", getChapterModel().getChapterId(), pageModel.getPageNumber(), jsonElement.toString());
            JsonObject pageData = jsonElement.getAsJsonArray().get(0).getAsJsonObject();
            //TODO 后面放到pageModel中
            width = pageModel.getWidth();
            height = pageModel.getHeight();
            JsonArray dataArray = pageData.get("data").getAsJsonArray();
            for (int j = 0; j < dataArray.size(); j++) {
                JsonArray lineArray = dataArray.get(j).getAsJsonArray();
                double top = getMaxLayoutValue(lineArray, "top");//first.get("top").getAsDouble();
                double textHeight = getMaxLayoutValue(lineArray, "height");//first.get("height").getAsDouble();
                String combineLine = combineTextJsonArray(lineArray);
                if (isEmpty(combineLine)) {
                    continue;
                }
                if (isInner3(lineArray, pageModel)) {
                    continue;
                }
                if (j < (dataArray.size() - 1)) {
                    String nextCombineLine = combineTextJsonArray(dataArray.get(j + 1).getAsJsonArray());
                    combineLine += nextCombineLine;
                } else if (j == dataArray.size()) {
                    combineLine += getNextPageFirstLine(pageModeList.get(i + 1));
                }
                logger.info("抽取{}章合并资产负债表，分析定位表格区域，分析文本：{}。", getChapterModel().getChapterId(), combineLine);
                if (isZCFZ(combineLine) && startPage <= 0) {
                    setTableUnitType(extractBizModel, combineLine);
                    setTableNameTextLayout(pageModel, extractBizModel, lineArray);
                    List<String> pageTableDataList = new ArrayList<>();
                    PageArea pageArea = new PageArea(pageModel.getPageNumber(), top + textHeight, 10, height, width);
                    try {
                        pageTableDataList.addAll(extractPdfByTable(new String[]{getDocumentModel().getPdfFilePath(), "-l", "-p", String.valueOf(pageArea.getPageNumber()), "-a", pageArea.getLayout(), "-f", "JSON"}));
                        if (CollectionUtils.isEmpty(pageTableDataList)) {
                            if (j >= (dataArray.size() - 3)) {
                                PageModel nextPageModel = getPageModelList().get(i + 1);
                                pageTableDataList.addAll(extractPdfByTable(new String[]{getDocumentModel().getPdfFilePath(), "-l", "-p", String.valueOf(pageArea.getPageNumber() + 1), "-a", nextPageModel.getDefaultPageArea().getLayout(), "-f", "JSON"}));
                            }
                        }
                    } catch (Exception e) {
                        logger.error(e.getMessage(), e);
                        continue;
                    }

                    for (int k = 0; k < pageTableDataList.size(); k++) {
                        String tableHeader = pageTableDataList.get(k);
                        logger.info("抽取{}章合并资产负债表，报表类型：{}，抽取合并财务报表表头信息，分析文本{}。", getChapterModel().getChapterId(), extractBizModel.getModelName(), tableHeader);
                        JsonArray pageDataArray = str2Json(tableHeader).getAsJsonArray();
                        JsonObject tableData = pageDataArray.get(0).getAsJsonObject();
                        JsonArray items = tableData.get("data").getAsJsonArray();
                        for (int l = 0; l < items.size(); l++) {
                            JsonArray itemArray = items.get(l).getAsJsonArray();
                            for (int m = 0; m < itemArray.size(); m++) {
                                if (l > 1 && yearIndexList.size() >= 4) {
                                    break;
                                }
                                try {
                                    JsonObject cell = itemArray.get(m).getAsJsonObject();
                                    String text = cell.get("text").getAsString();
                                    String year = null;
                                    if (isEmpty(text)) {
                                        continue;
                                    }
                                    text = replaceCRLF(text).trim();
                                    if (isZCFZ_NB(text)) {
                                        year = extractZCFZ_NB(text);//年报
                                        extractBizModel.addTable(year);
                                        logger.info("抽取{}章合并资产负债表，报表类型：{}，分析抽取财报年份：{}。", getChapterModel().getChapterId(), extractBizModel.getModelName(), year);
                                    } else if (isZCFZ_JB(text)) {//季报
                                        year = extractZCFZ_JB(text);
                                        extractBizModel.addTable(year);
                                        logger.info("抽取{}章合并资产负债表，报表类型：{}，分析抽取财报年份：{}。", getChapterModel().getChapterId(), extractBizModel.getModelName(), year);
                                    } else {
                                        logger.info("抽取{}章合并资产负债表，报表类型：{}，未知数据：{}。", getChapterModel().getChapterId(), extractBizModel.getModelName(), text);
                                    }
                                    if (!isEmpty(year)) {
                                        yearIndexList.add(new YearIndex(m, year));
                                    }
                                } catch (Exception e) {
                                    logger.error(e.getMessage(), e);
                                    continue;
                                }
                            }
                        }
                        logger.info("抽取{}章合并资产负债表，报表类型：{}，分析到抽取现金流量表年份列表：{}。", getChapterModel().getChapterId(), extractBizModel.getModelName(), yearIndexList);
                    }
                    if (yearIndexList.size() <= 1) {
                        logger.error("抽取{}章合并资产负债表，报表类型：{}，当前页码：{}，该财务报表可能存在问题，需确认！！！", getChapterModel().getChapterSeqNo(), extractBizModel.getModelName(), pageModel.getPageNumber());
                        continue;
                    }
                    pageAreas.add(pageArea);
                    logger.info("抽取{}章合并资产负债表，报表类型：{}，分析定位到合并财务报表表格区域，起始位置，页码：{}，表格区域：{}。", getChapterModel().getChapterId(), extractBizModel.getModelName(), pageModel.getPageNumber(), pageArea.getLayout());
                    startPage = pageModel.getPageNumber();
                    break;
                } else if (isLR(combineLine)) {
                    PageArea pageArea = new PageArea(pageModel.getPageNumber(), 50, 10, top, width);
                    pageAreas.add(pageArea);
                    logger.info("抽取{}章合并资产负债表，报表类型：{}，分析定位到合并财务报表表格区域，结束位置，页码：{}，表格区域：{}。", getChapterModel().getChapterId(), extractBizModel.getModelName(), pageModel.getPageNumber(), pageArea.getLayout());
                    endPage = pageModel.getPageNumber();
                    break;
                }
            }
            if (startPage > 0 && endPage > 0) {
                logger.info("抽取{}章合并资产负债表，报表类型：{}，已分析定位到合并财务报表位置，开始页码：{}，结束页码：{}。", getChapterModel().getChapterId(), extractBizModel.getModelName(), startPage, endPage);
                break;
            }
        }
        if (startPage <= 0 || endPage <= 0) {
            logger.error("抽取{}章合并资产负债表，报表类型：{}，分析定位合并财务报表表格区域失败！！！", getChapterModel().getChapterId(), extractBizModel.getModelName());
            return;
        }
        for (int i = 1; i < (endPage - startPage); i++) {
            PageArea pageArea = new PageArea(i + startPage, 50, 10, height, width);
            pageAreas.add(i, pageArea);
            logger.info("抽取{}章合并资产负债表，报表类型：{}，定位合并财务报表中间区域，页码：{}，表格区域：{}。", getChapterModel().getChapterId(), extractBizModel.getModelName(), (i + startPage), pageArea.getLayout());
        }
        logger.info("抽取{}章合并资产负债表，表格类型：{}，分析定位合并财务报表表格区域完成，起始页码：{}，结束页码：{}，页码总数：{}，开始抽取表格数据......", getChapterModel().getChapterId(), extractBizModel.getModelName(), startPage, endPage, pageAreas.size());
        try {
            extractCWBB(pageAreas, extractBizModel);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        logger.info("抽取{}章合并资产负债表，表格类型：{}，提取合并财务报表数据完成。", getChapterModel().getChapterId(), extractBizModel.getModelName());
        long t2 = System.currentTimeMillis();
        logger.info("抽取{}章合并资产负债表，表格类型：{}，表格区域：{}~{}页，耗时：{}毫秒。", getChapterModel().getChapterId(), extractBizModel.getModelName(), startPage, endPage, (t2 - t1));
    }

    /**
     * M-6-1现金流量
     * //TODO
     */
    private void extractM6XJLL() {
        ExtractBizModel extractBizModel = getChapterModel().getExtractBizModelMap().get("XJLL");
        long t1 = System.currentTimeMillis();
        logger.info("开始抽取{}章合并现金流量表......", getChapterModel().getChapterId());
        List<PageModel> pageModeList = getPageModelList();
        logger.info("开始抽取{}章合并现金流量表，分析页码总数：{}。", getChapterModel().getChapterId(), pageModeList.size());
        List<PageArea> pageAreas = new ArrayList<>();
        int startPage = 0, endPage = 0;
        double width = 0;
        double height = 0;
        logger.info("抽取{}章合并现金流量表，分析定位表格区域......", getChapterModel().getChapterId());
        for (int i = 0; i < pageModeList.size(); i++) {
            PageModel pageModel = pageModeList.get(i);
            JsonElement jsonElement = pageModel.getJsonTextData();
            logger.info("抽取{}章合并现金流量表，当前页码：{}，分析文本：{}。", getChapterModel().getChapterId(), pageModel.getPageNumber(), jsonElement.toString());
            JsonObject pageData = jsonElement.getAsJsonArray().get(0).getAsJsonObject();
            //TODO 后面放到pageModel中
            width = pageModel.getWidth();
            height = pageModel.getHeight();
            logger.info("抽取{}章合并现金流量表，width：{}，height：{}。", getChapterModel().getChapterId(), width, height);
            JsonArray dataArray = pageData.get("data").getAsJsonArray();
            for (int j = 0; j < dataArray.size(); j++) {
                JsonArray lineArray = dataArray.get(j).getAsJsonArray();
                double top = getMaxLayoutValue(lineArray, "top");//first.get("top").getAsDouble();
                double textHeight = getMaxLayoutValue(lineArray, "height");//first.get("height").getAsDouble();
                String combineLine = combineTextJsonArray(lineArray);
                if (isEmpty(combineLine)) {
                    continue;
                }
                try {
                    if (j < (dataArray.size() - 1)) {
                        String nextCombineLine = combineTextJsonArray(dataArray.get(j + 1).getAsJsonArray());
                        combineLine += nextCombineLine;
                    } else if (j == dataArray.size()) {
                        //TODO 按理说应该考虑到跨页，实际在M4不会出现这种情况，暂时不添加
                        combineLine += getNextPageFirstLine(pageModeList.get(i + 1));
                    }
                    if (isXJLL(combineLine)) {
                        setTableUnitType(extractBizModel, combineLine);
                        setTableNameTextLayout(pageModel, extractBizModel, lineArray);
                        PageArea pageArea = new PageArea(pageModel.getPageNumber(), top + textHeight, 10, height, width);
                        pageAreas.add(pageArea);
                        logger.info("抽取{}章合并现金流量表，分析定位到合并财务报表表格区域，起始位置，起始页码：{}，表格区域：{}。", getChapterModel().getChapterId(), pageModel.getPageNumber(), pageArea.getLayout());
                        startPage = pageModel.getPageNumber();
                        break;
//                } else if (isXJLL(combineLine) || isLR(combineLine)) {
                    } else if (isMGSCW(combineLine) && startPage > 0) {
                        PageArea pageArea = new PageArea(pageModel.getPageNumber(), 50, 10, top, width);
                        pageAreas.add(pageArea);
                        logger.info("抽取{}章合并现金流量表，分析定位到合并财务报表表格区域，结束位置，结束页码：{}，表格区域：{}。", getChapterModel().getChapterId(), pageModel.getPageNumber(), pageArea.getLayout());
                        endPage = pageModel.getPageNumber();
                        break;
                    }
                } catch (Exception e) {
                    logger.error(e.getMessage(), e);
                }
            }
            if (startPage > 0 && endPage > 0) {
                logger.info("抽取{}章合并现金流量表，已分析定位到合并财务报表位置，开始页码：{}，结束页码：{}。", getChapterModel().getChapterId(), startPage, endPage);
                break;
            }
        }
        if (startPage <= 0 || endPage <= 0) {
            logger.error("抽取{}章合并现金流量表，分析定位合并财务报表表格区域失败！！！", getChapterModel().getChapterId());
            return;
        }
        for (int i = 1; i < (endPage - startPage); i++) {
            PageArea pageArea = new PageArea(i + startPage, 50, 10, height, width);
            pageAreas.add(i, pageArea);
            logger.info("抽取{}章合并现金流量表，分析定位合并财务报表中间区域，页码：{}，表格区域：{}。", getChapterModel().getChapterId(), (i + startPage), pageArea.getLayout());
        }
        logger.info("抽取{}章合并现金流量表，已分析定位到合并现金流量表位置，起始页码：{}，结束页码：{}，页码总数：{}，开始抽取表格数据......", getChapterModel().getChapterId(), startPage, endPage, pageAreas.size());
        try {
            extractCWBB(pageAreas, extractBizModel);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        logger.info("抽取{}章合并现金流量表，提取合并财务报表数据完成。", getChapterModel().getChapterId());
        long t2 = System.currentTimeMillis();
        logger.info("抽取{}章合并现金流量表完成，表格区域：{}~{}页，耗时：{}毫秒。", getChapterModel().getChapterId(), startPage, endPage, (t2 - t1));
    }

    /**
     * 通用格式抽取会计报表
     * 1、资产负债表
     * 2、利润表
     * 3、现金流量表
     */
    private void extractCWBB(List<PageArea> pageAreaList, ExtractBizModel extractBizModel) {
        long t1 = System.currentTimeMillis();
        logger.info("开始抽取{}章节财务报表数据，报表类型：{}......", getChapterModel().getChapterId(), extractBizModel.getModelName());
        zcfzTokenizer.loadCoreSynonyms(extractBizModel);
        List<String> tableDataList = new ArrayList<>();
        int startPage = 0;
        for (int i = 0; i < pageAreaList.size(); i++) {
            try {
                PageArea pageArea = pageAreaList.get(i);
                if (i == 0) {
                    startPage = pageArea.getPageNumber();
                }
                logger.info("抽取{}章合并财务报表，报表类型：{}，当前页码：{}，表格位置：{}，抽取表格数据......", getChapterModel().getChapterId(), extractBizModel.getModelName(), pageArea.getPageNumber(), pageArea.getLayout());
                List<String> pageTableDataList = extractPdfByTable(new String[]{getDocumentModel().getPdfFilePath(), "-l", "-p", String.valueOf(pageArea.getPageNumber()), "-a", pageArea.getLayout(), "-f", "JSON"});
                logger.info("抽取{}章合并财务报表，报表类型：{}，当前页码：{}，抽取当前表格数据完成，表格数量：{}，表格数据内容：{}。", getChapterModel().getChapterId(), extractBizModel.getModelName(), pageArea.getPageNumber(), pageTableDataList.size(), pageTableDataList);
                tableDataList.addAll(pageTableDataList);
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
            }
        }
        if (tableDataList.isEmpty()) {
            logger.error("抽取{}章合并财务报表，报表类型：{}，已定位到表格位置，但未能提取表格内容，中断后续执行！！！", getChapterModel().getChapterId(), extractBizModel.getModelName());
            return;
        }
        int thresholdValue = 5;
        List<YearIndex> yearIndexList = new ArrayList<>();
        for (int i = 0; i < tableDataList.size(); i++) {
            String tableHeader = tableDataList.get(i);
            logger.info("抽取{}章合并财务报表，报表类型：{}，抽取合并财务报表表头信息，分析文本{}。", getChapterModel().getChapterId(), extractBizModel.getModelName(), tableHeader);
            JsonArray pageData = str2Json(tableHeader).getAsJsonArray();
            JsonObject tableData = pageData.get(0).getAsJsonObject();
            JsonArray items = tableData.get("data").getAsJsonArray();
            try {
                clearEmptyCell(items, 5, 0);
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
            }
            for (int l = 0; l < items.size(); l++) {
                if (l > 1 && yearIndexList.size() >= 3) {
                    break;
                }
                JsonArray itemArray = items.get(l).getAsJsonArray();
                for (int j = 0; j < itemArray.size(); j++) {
                    JsonObject cell = itemArray.get(j).getAsJsonObject();
                    String text = cell.get("text").getAsString();
                    String year = null;
                    if (isEmpty(text)) {
                        continue;
                    }
                    text = replaceCRLF(text).trim();
                    if (isZCFZ_NB(text)) {
                        year = extractZCFZ_NB(text);//年报
                        extractBizModel.addTable(year);
                        logger.info("抽取{}章合并财务报表，报表类型：{}，分析抽取财报年份：{}。", getChapterModel().getChapterId(), extractBizModel.getModelName(), year);
                    } else if (isZCFZ_JB(text)) {//季报
                        year = extractZCFZ_JB(text);
                        extractBizModel.addTable(year);
                        logger.info("抽取{}章合并财务报表，报表类型：{}，分析抽取财报年份：{}。", getChapterModel().getChapterId(), extractBizModel.getModelName(), year);
                    } else {
                        logger.info("抽取{}章合并财务报表，报表类型：{}，未知数据：{}。", getChapterModel().getChapterId(), extractBizModel.getModelName(), text);
                    }
                    if (!isEmpty(year)) {
                        boolean isExist = false;
                        for (int k = 0; k < yearIndexList.size(); k++) {
                            YearIndex tmp = yearIndexList.get(k);
                            if (tmp.getYear().equalsIgnoreCase(year)) {
                                isExist = true;
                                break;
                            }
                        }
                        if (!isExist) {
                            yearIndexList.add(new YearIndex(j, year));
                        }
                    }
                }
            }
            if (yearIndexList.size() >= 4) {
                break;
            }
            logger.info("抽取{}章合并财务报表，报表类型：{}，分析到抽取现金流量表年份列表：{}。", getChapterModel().getChapterId(), extractBizModel.getModelName(), yearIndexList);
        }
        if (yearIndexList.isEmpty()) {
            logger.info("抽取{}章合并财务报表，报表类型：{}，未能提取合并财报年份，中断后续操作！！！", getChapterModel().getChapterId(), extractBizModel.getModelName());
            return;
        }
        ExtractItem extractItem = null;
        logger.info("抽取{}章合并财务报表，报表类型：{}，定位表格位置，提取表格内容已完成，开始提取财报数据......", getChapterModel().getChapterId(), extractBizModel.getModelName());
        for (int i = 0; i < tableDataList.size(); i++) {
            String tableData = tableDataList.get(i);
            int pageNum = i + startPage;
            logger.info("抽取{}章合并财务报表，报表类型：{}，数据：{}。", getChapterModel().getChapterId(), extractBizModel.getModelName(), tableData);
            JsonArray pageData = str2Json(tableData).getAsJsonArray();
            JsonObject var1 = pageData.get(0).getAsJsonObject();
            JsonArray var2 = var1.get("data").getAsJsonArray();
            //TODO offset后续还需动态调整，有的报表可能跨2行
            //TODO offset 还需要调整！！！
            thresholdValue = yearIndexList.size() + 1;
            try {
                clearEmptyCell(var2, thresholdValue, 1);
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
            }

            for (int j = 0; j < var2.size(); j++) {
                JsonArray var3 = var2.get(j).getAsJsonArray();
                if (var3.size() < yearIndexList.size() + 1) {
                    continue;
                }
                JsonElement textElement = var3.get(0).getAsJsonObject();
                String itemName = replaceCRLF(((JsonObject) textElement).get("text").getAsString());
                if (isEmpty(itemName)) {
                    continue;
                }
                logger.info("抽取{}章合并财务报表，报表类型：{}，第{}条数据，内容：{}。", getChapterModel().getChapterId(), extractBizModel.getModelName(), j, var3.toString());
                extractItem = extractBizModel.getExtractItemBySynonym(itemName);
                if (extractItem == null) {
                    logger.error("抽取{}章合并财务报表，报表类型：{}，会计科目名称：{}，未能从会计科目列表获取到对应会计科目，继续通过相似度分析......", getChapterModel().getChapterId(), extractBizModel.getModelName(), itemName);
                    for (String synonym : extractBizModel.getSynonyms()) {
                        double similarity = getSimilarAnalyser().similarity(synonym, itemName);
                        if (similarity > 0.9) {
                            extractItem = extractBizModel.getExtractItemBySynonym(synonym);
                            break;
                        }
                    }
                }
                if (extractItem == null) {
                    extractItem = zcfzTokenizer.splitWords3(extractBizModel, itemName);
                    logger.error("抽取{}章合并财务报表，报表类型：{}，经过语义相似度、词库精准匹配分析，还是未能获取到会计科目，通过切词提取......", getChapterModel().getChapterId(), extractBizModel.getModelName());
                    if (extractItem == null) {
                        logger.error("抽取{}章合并财务报表，报表类型：{}，经过语义相似度、词库精准匹配分析，切词分析，还是未能获取到会计科目，中断后续操作！！！", getChapterModel().getChapterId(), extractBizModel.getModelName());
                        continue;
                    }
                }
                logger.info("抽取{}章合并财务报表，报表类型：{}，分析到会计科目名称：{}，数据内容：{}。", getChapterModel().getChapterId(), extractBizModel.getModelName(), itemName, var3.toString());
                for (int k = 0; k < yearIndexList.size(); k++) {
                    YearIndex yearIndex = yearIndexList.get(k);
                    int index = yearIndex.getIndex();
                    String year = yearIndex.getYear();
                    try {
                        JsonElement amtElement = var3.get(index);
                        ExtractItem newExtractItem = (ExtractItem) BeanUtils.cloneBean(extractItem);
                        newExtractItem.setUnit(extractBizModel.getUnitType());
//                        JsonElement pageTableData = getAssignPageModel(pageNum).getJsonTextData();

                        setKV(newExtractItem, textElement, amtElement, getAssignPageModel(pageNum).getJsonTextData());
                        newExtractItem.getKey().setPageNumber(pageNum);
                        if (extractBizModel.getTable(year) == null) {
                            extractBizModel.addTable(year);
                        }
                        if (!extractBizModel.getTable(year).containsKey(extractItem.getItemName())) {
                            extractBizModel.getTable(year).put(newExtractItem.getItemName(), newExtractItem);
                        }
                    } catch (IllegalAccessException e) {
                        logger.error(e.getMessage(), e);
                    } catch (InstantiationException e) {
                        logger.error(e.getMessage(), e);
                    } catch (InvocationTargetException e) {
                        logger.error(e.getMessage(), e);
                    } catch (NoSuchMethodException e) {
                        logger.error(e.getMessage(), e);
                    }
                }
                continue;
            }
        }
        zcfzTokenizer.unloadCoreSynonyms(extractBizModel);
        long t2 = System.currentTimeMillis();
        logger.info("抽取{}章节财务报表数据完成，报表类型：{}，耗时：{}毫秒。", getChapterModel().getChapterId(), extractBizModel.getModelName(), (t2 - t1));
    }

    /**
     * M-6-1利润表
     */
    private void extractM6LR() {
        ExtractBizModel extractBizModel = getChapterModel().getExtractBizModelMap().get("LR");
        long t1 = System.currentTimeMillis();
        logger.info("开始抽取{}章合并利润表......", getChapterModel().getChapterId());
        List<PageModel> pageModeList = getPageModelList();
        logger.info("开始抽取{}章合并利润表，页码总数：{}。", getChapterModel().getChapterId(), pageModeList.size());
        List<PageArea> pageAreas = new ArrayList<>();
        int startPage = 0, endPage = 0;
        double width = 0, height = 0;
        logger.info("抽取{}章合并利润表，分析定位表格区域......", getChapterModel().getChapterId());
        for (int i = 0; i < pageModeList.size(); i++) {
            PageModel pageModel = pageModeList.get(i);
            JsonElement jsonElement = pageModel.getJsonTextData();
            logger.info("抽取{}章合并利润表，当前页码：{}，分析文本：{}。", getChapterModel().getChapterId(), pageModel.getPageNumber(), jsonElement.toString());
            JsonObject pageData = jsonElement.getAsJsonArray().get(0).getAsJsonObject();
            //TODO 后面放到pageModel中
            width = pageModel.getWidth();
            height = pageModel.getHeight();
            logger.info("抽取{}章合并利润表，width：{}，height：{}。", getChapterModel().getChapterId(), width, height);
            JsonArray dataArray = pageData.get("data").getAsJsonArray();
            for (int j = 0; j < dataArray.size(); j++) {
                JsonArray lineArray = dataArray.get(j).getAsJsonArray();
                double top = getMaxLayoutValue(lineArray, "top");//first.get("top").getAsDouble();
                double textHeight = getMaxLayoutValue(lineArray, "height");//first.get("height").getAsDouble();
                String combineLine = combineTextJsonArray(lineArray);
                if (isEmpty(combineLine)) {
                    continue;
                }
                if (j < (dataArray.size() - 1)) {
                    String nextCombineLine = combineTextJsonArray(dataArray.get(j + 1).getAsJsonArray());
                    combineLine += nextCombineLine;
                } else if (j == dataArray.size()) {
                    //TODO 按理说应该考虑到跨页，实际在M4不会出现这种情况，暂时不添加
                    combineLine += getNextPageFirstLine(pageModeList.get(i + 1));
                }
                if (isLR(combineLine)) {
                    setTableUnitType(extractBizModel, combineLine);
                    setTableNameTextLayout(pageModel, extractBizModel, lineArray);
                    PageArea pageArea = new PageArea(pageModel.getPageNumber(), top + textHeight, 20, height, width);
                    pageAreas.add(pageArea);
                    logger.info("抽取{}章合并利润表，分析定位到合并财务报表表格区域，起始位置，页码：{}，表格区域：{}。", getChapterModel().getChapterId(), pageModel.getPageNumber(), pageArea.getLayout());
                    startPage = pageModel.getPageNumber();
                    continue;
                } else if (isXJLL(combineLine)) {
                    PageArea pageArea = new PageArea(pageModel.getPageNumber(), 50, 20, top, width);
                    pageAreas.add(pageArea);
                    logger.info("抽取{}章合并利润表，分析定位到合并财务报表表格区域，结束位置，页码：{}，表格区域：{}。", getChapterModel().getChapterId(), pageModel.getPageNumber(), pageArea.getLayout());
                    endPage = pageModel.getPageNumber();
                    break;
                }
            }
            if (startPage > 0 && endPage > 0) {
                logger.info("抽取{}章合并利润表，已分析定位到合并财务报表表格位置，开始页码：{}，结束页码：{}。", getChapterModel().getChapterId(), startPage, endPage);
                break;
            }
        }
        if (startPage <= 0 || endPage <= 0) {
            logger.error("抽取{}章合并利润表，分析定位合并财务报表表格区域失败！！！", getChapterModel().getChapterId());
            return;
        }
        for (int i = 1; i < (endPage - startPage); i++) {
            PageArea pageArea = new PageArea(i + startPage, 50, 20, height, width);
            pageAreas.add(i, pageArea);
            logger.info("抽取{}章合并利润表，分析定位合并财务报表中间区域，页码：{}，表格区域：{}。", getChapterModel().getChapterId(), (i + startPage), pageArea.getLayout());
        }
        logger.info("抽取{}章合并利润表，分析定位到合并财务报表表格位置，起始页码：{}，结束页码：{}，页码总数：{}，开始抽取表格数据......", getChapterModel().getChapterId(), startPage, endPage, pageAreas.size());
        try {
            extractCWBB(pageAreas, extractBizModel);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        logger.info("抽取{}章合并利润表，提取合并财务报表数据完成。", getChapterModel().getChapterId());
        long t2 = System.currentTimeMillis();
        logger.info("抽取{}章合并利润表完成，表格区域：{}~{}页，耗时：{}毫秒。", getChapterModel().getChapterId(), startPage, endPage, (t2 - t1));
    }

    /**
     * 偿债能力
     */
    private void extractM6CZNL2() {
        long t1 = System.currentTimeMillis();
        logger.info("开始抽取：{}章偿债能力业务模型......", getChapterModel().getChapterId());
        List<PageModel> pageModelList = getPageModelList();
        PageModel pageModel = null;
        List<PageArea> pageAreaList = new ArrayList<>();
        TextLayout startTextLayout = null;
        TextLayout endTextLayout = null;
        ExtractBizModel extractBizModel = getChapterModel().getExtractBizModelMap().get("CZNL");
        for (int i = 0; i < pageModelList.size(); i++) {
            pageModel = pageModelList.get(i);
            if (pageModel == null) {
                continue;
            }
            JsonArray itemArray = getPageDataArray(pageModel);
            for (int j = 0; j < itemArray.size(); j++) {
                JsonArray items = itemArray.get(j).getAsJsonArray();
                String combineLine = combineTextJsonArray(items);
                if (isEmpty(combineLine)) {
                    continue;
                }
                if (j == (itemArray.size() - 1)) {
                    if (getPageModelBottomPageNum(items) > 0) {
                        logger.info("抽取：{}章偿债能力业务模型，当前页码：{}，已分析到该页末尾，到下一页定位偿债能力信息表位置。", getChapterModel().getChapterId(), pageModel.getPageNumber());
                        break;
                    }
                }
                logger.info("抽取：{}章偿债能力业务模型，分析文本：{}。", getChapterModel().getChapterId(), combineLine);
                if (isCWZB_CZNL(combineLine)) {
                    setTableNameTextLayout(pageModel, extractBizModel, items);
                    logger.info("抽取：{}章偿债能力业务模型，分析定位到偿债能力表格开始位置，开始页码：{}，表头信息：{}。", getChapterModel().getChapterId(), combineLine);
                    startTextLayout = createKVTextLayout(pageModel, items);
                    continue;
                }
                if (isInner3(items, pageModel)) {
                    continue;
                } else if (startTextLayout != null) {
                    if (isAmtUnit(combineLine)) {
                        setTableUnitType(extractBizModel, combineLine);
                        continue;
                    }
                    endTextLayout = createKVTextLayout(pageModel, items);
                    logger.info("抽取：{}章偿债能力业务模型，分析定位到偿债能力表格结束位置，结束页码：{}。", getChapterModel().getChapterId(), combineLine);
                    pageAreaList.addAll(createPageArea(startTextLayout, endTextLayout));
                    break;
//                    startTextLayout = null;
//                    endTextLayout = null;
//                    continue;
                }
            }
            if (startTextLayout != null && endTextLayout != null) {
                break;
            }
        }
        if (CollectionUtils.isEmpty(pageAreaList)) {
            logger.error("抽取：{}章偿债能力业务模型，分析定位偿债能力表格位置失败！！！", getChapterModel().getChapterId());
            return;
        }
        logger.info("抽取：{}章偿债能力业务模型，分析定位到偿债能力表格位置，开始提取财务指标数据......", getChapterModel().getChapterId());
        try {
            extractCWBB(pageAreaList, extractBizModel);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }

        logger.info("抽取{}章偿债能力业务模型，财务指标数据结构：{}。", getChapterModel().getChapterId(), obj2Json(extractBizModel));
        long t2 = System.currentTimeMillis();
        logger.info("抽取{}章偿债能力业务模型完成，耗时：{}毫秒。", getChapterModel().getChapterId(), (t2 - t1));
    }


    private void extractM6YYNL2() {
        long t1 = System.currentTimeMillis();
        logger.info("开始抽取：{}章运营能力业务模型......", getChapterModel().getChapterId());
        List<PageModel> pageModelList = getPageModelList();
        PageModel pageModel = null;
        List<PageArea> pageAreaList = new ArrayList<>();
        TextLayout startTextLayout = null;
        TextLayout endTextLayout = null;
        ExtractBizModel extractBizModel = getChapterModel().getExtractBizModelMap().get("YYNL");
        for (int i = 0; i < pageModelList.size(); i++) {
            pageModel = pageModelList.get(i);
            if (pageModel == null) {
                continue;
            }
            JsonArray itemArray = getPageDataArray(pageModel);
            for (int j = 0; j < itemArray.size(); j++) {
                JsonArray items = itemArray.get(j).getAsJsonArray();
                String combineLine = combineTextJsonArray(items);
                if (isEmpty(combineLine)) {
                    continue;
                }
                if (j == (itemArray.size() - 1)) {
                    if (getPageModelBottomPageNum(items) > 0) {
                        logger.info("抽取：{}章运营能力业务模型，当前页码：{}，已分析到该页末尾，到下一页定位营运能力表格位置。", getChapterModel().getChapterId(), pageModel.getPageNumber());
                        break;
                    }
                }
                if (isCWZB_YYNL(combineLine)) {
                    setTableNameTextLayout(pageModel, extractBizModel, items);
                    logger.info("抽取：{}章运营能力业务模型，分析定位到营运能力表格起始位置，开始页码：{}，表头信息：{}。", getChapterModel().getChapterId(), combineLine);
                    startTextLayout = createKVTextLayout(pageModel, items);
                    continue;
                }
                if (isInner3(items, pageModel)) {
                    continue;
                } else if (startTextLayout != null) {
                    if (isAmtUnit(combineLine)) {
                        setTableUnitType(extractBizModel, combineLine);
                        continue;
                    }
                    endTextLayout = createKVTextLayout(pageModel, items);
                    logger.info("抽取：{}章运营能力业务模型，分析定位到营运能力表格结束位置，结束页码：{}。", getChapterModel().getChapterId(), combineLine);
                    pageAreaList.addAll(createPageArea(startTextLayout, endTextLayout));
                    break;
//                    startTextLayout = null;
//                    endTextLayout = null;
//                    continue;
                }
            }
            if (startTextLayout != null && endTextLayout != null) {
                break;
            }
        }
        if (CollectionUtils.isEmpty(pageAreaList)) {
            logger.info("抽取：{}章运营能力业务模型，分析定位运营能力表格位置失败！！！", getChapterModel().getChapterId());
            return;
        }
        logger.info("抽取：{}章运营能力业务模型，分析定位到运营能力表格位置，开始提取财务指标表格数据......", getChapterModel().getChapterId());
        try {
            extractCWBB(pageAreaList, extractBizModel);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }

        logger.info("抽取{}章运营能力业务模型，财务指标数据结构：{}。", getChapterModel().getChapterId(), obj2Json(extractBizModel));
        long t2 = System.currentTimeMillis();
        logger.info("抽取{}章运营能力业务模型完成，耗时：{}毫秒。", getChapterModel().getChapterId(), (t2 - t1));
    }

    private void extractM6YLNL2() {
        long t1 = System.currentTimeMillis();
        logger.info("开始抽取：{}章盈利能力业务模型......", getChapterModel().getChapterId());
        List<PageModel> pageModelList = getPageModelList();
        PageModel pageModel = null;
        List<PageArea> pageAreaList = new ArrayList<>();
        TextLayout startTextLayout = null;
        TextLayout endTextLayout = null;
        ExtractBizModel extractBizModel = getChapterModel().getExtractBizModelMap().get("YLNL");
        for (int i = 0; i < pageModelList.size(); i++) {
            pageModel = pageModelList.get(i);
            if (pageModel == null) {
                continue;
            }
            JsonArray itemArray = getPageDataArray(pageModel);
            for (int j = 0; j < itemArray.size(); j++) {
                JsonArray items = itemArray.get(j).getAsJsonArray();
                String combineLine = combineTextJsonArray(items);
                if (isEmpty(combineLine)) {
                    continue;
                }
                if (j == (itemArray.size() - 1)) {
                    if (getPageModelBottomPageNum(items) > 0) {
                        logger.info("抽取：{}章盈利能力业务模型，当前页码：{}，到下一页定位盈利能力信息表起始位置。", getChapterModel().getChapterId(), pageModel.getPageNumber());
                        break;
                    }
                }
                if (isCWZB_YLNL(combineLine)) {
                    setTableNameTextLayout(pageModel, extractBizModel, items);
                    logger.info("抽取：{}章盈利能力业务模型，分析定位到盈利能力表格起始位置，开始页码：{}，表头信息：{}。", getChapterModel().getChapterId(), combineLine);
                    startTextLayout = createKVTextLayout(pageModel, items);
                    continue;
                }
                if (isInner3(items, pageModel)) {
                    continue;
                } else if (startTextLayout != null) {
                    if (isAmtUnit(combineLine)) {
                        setTableUnitType(extractBizModel, combineLine);
                        continue;
                    }
                    endTextLayout = createKVTextLayout(pageModel, items);
                    logger.info("抽取：{}章盈利能力业务模型，分析定位到盈利能力表格结束位置，结束页码：{}。", getChapterModel().getChapterId(), combineLine);
                    pageAreaList.addAll(createPageArea(startTextLayout, endTextLayout));
                    break;
//                    startTextLayout = null;
//                    endTextLayout = null;
//                    continue;
                }
            }
            if (startTextLayout != null && endTextLayout != null) {
                break;
            }
        }
        if (CollectionUtils.isEmpty(pageAreaList)) {
            logger.info("抽取：{}章盈利能力业务模型，分析定位盈利能力表格位置失败！！！", getChapterModel().getChapterId());
            return;
        }
        logger.info("抽取：{}章盈利能力业务模型，分析定位到盈利能力表格位置，开始提取财务报表数据......", getChapterModel().getChapterId());
        try {
            extractCWBB(pageAreaList, extractBizModel);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        logger.info("抽取{}章盈利能力业务模型，财务报表数据结构：{}。", getChapterModel().getChapterId(), obj2Json(extractBizModel));
        long t2 = System.currentTimeMillis();
        logger.info("抽取{}章盈利能力业务模型完成，耗时：{}毫秒。", getChapterModel().getChapterId(), (t2 - t1));
    }
}

class YearIndex {

    public YearIndex(Integer index, String year) {
        this.index = index;
        this.year = year;
    }

    int index;

    public int getIndex() {
        return index;
    }

    public void setIndex(int index) {
        this.index = index;
    }

    public String getYear() {
        return year;
    }

    public void setYear(String year) {
        this.year = year;
    }

    String year;

    @Override
    public String toString() {
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("Year").append("=").append(year).append(",").append("Index").append("=").append(index);
        return stringBuilder.toString();
    }
}